#Copyright Okhtay Shoghi 2008

class Hash
    def require *keys
        keys.each do |k| 
            has_key? k or raise "ArgumentError: missing required field #{k}"
        end
    end

    def defaults defaults={}
        defaults.each_pair do |nk,nv|
            self[nk]=nv unless has_key? nk
        end

        if (self.has_key?('unset'))
            self['unset'].each do |key|
                self.delete(key)
            end
            self.delete('unset')
        end
    end

	def to_query_string
		params = []
		self.each do |k,v|
			params << "#{k}=#{v}"
		end
		return params.join("&")
	end

    def replace_vals hash
        hash.each_pair do |k,v|
            self[k] = v
        end
        return self
    end

    def unset(key)
        self.delete(key)
        return self
    end

    def diff (x)
        if (x.class != Hash)
            return [self, x]
        end
        
        keys = (self.keys + x.keys).uniq
        diffs = {}
        
        keys.each do |key|
            if (self[key] != x[key])
                if(self[key].class == x[key].class && (self[key].class == Hash || self[key].class == Array))
                    delta = self[key].diff(x[key])
                    diffs[key] = delta if (delta != {} && delta != [])
                else
                    diffs[key] = "#{self[key].class}:#{self[key].inspect} vs #{x[key].class}:#{x[key].inspect}" if (self[key] != x[key])
                end
            end
        end
        
        return diffs
    end

    def persist vars
        vars.each_pair do |k,v|
            if self.has_key? k
                puts "saving setting #{k} = #{self[k]}"
                vars[k] = self[k]
            else
                puts "loading saved setting #{k} = #{v}"
                self[k] = v
            end
        end
    end

    def set_value(key,value)
        self[key] = value;
        return self
    end

    def <=> hash
        return self.vals_to_str <=> hash.vals_to_str
    end

    def vals_to_str
        str = ""
        self.keys.sort.each do |key|
            str += "#{key}=>#{self[key]},"
        end
        return str
    end

	def method_missing(name, *args)
		key = name.to_s
		
		if (key.match(/=$/))
			key.chop!
			
			if self.has_key?(key)
				self[key] = args[0]
				return self
			end
		end

		return self[key] #if self.has_key?(key)
		return super(name, args)
	end
end
   
class Array
    def diff x
        if (x.class != Array)
            return [self, x]
        end
        
        diffs = {}
        self.each_index do |i|
            if(self[i].class == x[i].class && (self[i].class == Hash || self[i].class == Array))
                delta = self[i].diff(x[i])
                diffs[i] = delta if (delta != {} && delta != [])
            else 
                diffs[i] = "#{self[i]} vs #{x[i]}" if (self[i] != x[i])
            end
        end
        
        return diffs
    end
	
	def sum
		return self.inject(:+).to_f
	end
	
	def avg
		return (self.inject(:+).to_f/self.length.to_f)
	end
	
	def to_h
		return nil if (self.length % 2 == 1)
		h = {}
		
		(0..(self.length-1)).step(2) do |i|
			h[self[i]] = self[i+1]
		end
		
		return h
	end
end

class NilClass
    def diff x
        if (x != nil)
            return "nil vs #{x.inspect}"
        end
        
        return false
    end    
	
	def each
	end
end




















